#include <gtk/gtk.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <assert.h>
#include <errno.h>
#include <string.h>

#include "config.h"

#define CONFIG_NAME "ictray"
enum{
	CHMOD_FAILED,
}ConfigErrorCodes;

static void _init(config_t *config)
{
	config->delay = 60;
	config->password = g_strdup("password");
	config->player = g_strdup("mplayer");
	config->login = g_strdup("login");
}

static char* _config_name()
{
	return g_strdup_printf("%s/.%s", getenv("HOME"), CONFIG_NAME);
}


void config_free(config_t *config)
{
	g_free(config->login);
	g_free(config->password);
	g_free(config->player);
	memset(config, 0, sizeof(*config));
}


#define check(val, dst, label)					\
	do											\
		if(val){								\
			g_propagate_error(dst, val);		\
			goto label;							\
		}										\
	while(0)

gboolean config_save(config_t *config, GError **error)
{
	GKeyFile *kf = NULL;
	char *fname = _config_name();
	char *contents = NULL;
	size_t contents_len = 0;
	GError *err = NULL;

	assert(fname);
	
	kf = g_key_file_new();
	g_key_file_set_string(kf, "main", "login", config->login);
	g_key_file_set_string(kf, "main", "password", config->password);
	g_key_file_set_string(kf, "main", "player", config->player);
	g_key_file_set_integer(kf, "main", "delay", config->delay);

	contents = g_key_file_to_data(kf, &contents_len, &err);
	check(err, error, cleanup);
	g_file_set_contents(fname, contents, contents_len, &err);
	check(err, error, cleanup);
	int ch_ret = chmod(fname, S_IRUSR|S_IWUSR);
	if(ch_ret < 0){
		g_set_error(error, g_quark_from_string("config-domain"), CHMOD_FAILED,
					"chmod failed: %s", strerror(errno));
		goto cleanup;
	}

 cleanup:
	if(contents)
		g_free(contents);
	if(fname)
		g_free(fname);
	if(kf)
		g_key_file_free(kf);
	
	return err == NULL;
}

gboolean config_load(config_t *config, GError **error)
{
	char *fname = NULL;
	GKeyFile *kf = NULL;
	char *pass, *player, *login;
	int delay;
	GError *err = NULL;

	config_free(config);
	_init(config);
	
	kf = g_key_file_new();
	assert(kf);

	fname = _config_name();
	assert(fname);

	g_key_file_load_from_file(kf, fname, 0, &err);
	check(err, error, cleanup);
	
	login = g_key_file_get_string(kf, "main", "login", &err);
	check(err, error, cleanup);
	pass = g_key_file_get_string(kf, "main", "password", &err);
	check(err, error, cleanup);
	player = g_key_file_get_string(kf, "main", "player", &err);
	check(err, error, cleanup);
	delay = g_key_file_get_integer(kf, "main", "delay", &err);
	check(err, error, cleanup);

	config->login = login;
	config->password = pass;
	config->player = player;
	config->delay = delay;
	
 cleanup:
	if(kf)
		g_key_file_free(kf);
	if(fname)
		g_free(fname);	

	return err == NULL;
}

#undef check

static void _dialog_cb(GtkWidget *dialog, gint response, gpointer data)
{
	if(response == GTK_RESPONSE_OK){
		int delay;
		const char *pass, *player, *login;
		GtkWidget *pass_w, *delay_w, *player_w, *login_w;
		config_t *config;

		login_w = g_object_get_data(G_OBJECT(dialog), "login");
		delay_w = g_object_get_data(G_OBJECT(dialog), "delay");
		pass_w = g_object_get_data(G_OBJECT(dialog), "pass");
		player_w = g_object_get_data(G_OBJECT(dialog), "player");
		config = g_object_get_data(G_OBJECT(dialog), "config");
	
		delay = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(delay_w));
		login = gtk_entry_get_text(GTK_ENTRY(login_w));;
		pass = gtk_entry_get_text(GTK_ENTRY(pass_w));
		player = gtk_entry_get_text(GTK_ENTRY(player_w));

		config_free(config);

		config->login = g_strdup(login);
		config->password = g_strdup(pass);
		config->player = g_strdup(player);
		config->delay = delay;
		
		//save
		config_save(config, NULL);
	}

	gtk_widget_destroy(dialog);
	
	ConfigCallback cb = g_object_get_data(G_OBJECT(dialog), "callback");
	g_idle_add((GSourceFunc)cb, data);
}

void config_run_dialog(config_t *current, ConfigCallback cb, gpointer data)
{
	GtkWidget *dialog = gtk_dialog_new_with_buttons("ic client params", NULL, 
													GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, 
													GTK_STOCK_OK, GTK_RESPONSE_OK,
													0);
	
	GtkWidget *delay, *login, *pass, *player, *box, *vbox;

	//create widgets and setup
	delay = gtk_spin_button_new_with_range(0, 60*60, 5);
	login = gtk_entry_new();
	pass = gtk_entry_new();
	player = gtk_entry_new();
	vbox = gtk_vbox_new(TRUE, TRUE);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(delay), current->delay);
	gtk_spin_button_set_digits(GTK_SPIN_BUTTON(delay), 0);
	gtk_entry_set_text(GTK_ENTRY(login), current->login);
	gtk_entry_set_text(GTK_ENTRY(pass), current->password);
	gtk_entry_set_text(GTK_ENTRY(player), current->player);

	//widges table
	struct {
		char *name;
		GtkWidget *widget;
	} table[] = {
		{"Login", login},
		{"Password", pass},
		{"Delay", delay},
		{"Player", player},
	};

	for(int i = 0; i<G_N_ELEMENTS(table); i++){
		box = gtk_hbox_new(TRUE, TRUE);
		gtk_container_add (GTK_CONTAINER (box), gtk_label_new(table[i].name));
		gtk_container_add (GTK_CONTAINER (box), table[i].widget);
		gtk_container_add (GTK_CONTAINER (vbox), box);
	}
	gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), vbox);

	//set some data to dialog
	g_object_set_data(G_OBJECT(dialog), "login", login);
	g_object_set_data(G_OBJECT(dialog), "delay", delay);
	g_object_set_data(G_OBJECT(dialog), "pass", pass);
	g_object_set_data(G_OBJECT(dialog), "player", player);
	g_object_set_data(G_OBJECT(dialog), "config", current);
	g_object_set_data(G_OBJECT(dialog), "callback", cb);

	//run
	g_signal_connect(dialog, "response", G_CALLBACK (_dialog_cb), data);
	gtk_widget_show_all(dialog);
}
